package xyz.weblade.context.event;

import cn.hutool.core.util.ClassUtil;
import xyz.weblade.beans.BeanFactoryAware;
import xyz.weblade.beans.BeansException;
import xyz.weblade.beans.factory.BeanFactory;
import xyz.weblade.context.ApplicationEvent;
import xyz.weblade.context.ApplicationListener;
import xyz.weblade.util.ClassUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Set;

public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {
    public final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new LinkedHashSet<>();

    private BeanFactory beanFactory;

    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
    }

    @Override
    public void removeApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.remove(listener);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event){
        LinkedList<ApplicationListener> allListeners = new LinkedList<>();
        for (ApplicationListener<ApplicationEvent> listener : applicationListeners) {
            if (supportsEvent(listener,event))allListeners.add(listener);
        }
        return allListeners;
    }

    protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener,ApplicationEvent event){
        Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();
        //按照CglibSubclassingInstantiationStrategy 和 SimpleInstantiationStrategy 不同实例化类型，需要判断后获取目标 class
        Class<?> targetClass = ClassUtils.isCglibProxyClass(listenerClass) ? listenerClass.getSuperclass() : listenerClass;
        //public class CustomEventListener implements ApplicationListener<CustomEvent>
        //先拿到字符串”xyz.weblade.context.ApplicationListener<CustomEvent> “
        Type genericInterface = targetClass.getGenericInterfaces()[0];
        //再拿到"class xyz.weblade.test.event.CustomEvent“
        Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
        //字符串形式”xyz.weblade.test.event.CustomEvent“
        String className = actualTypeArgument.getTypeName();
        Class<?> eventClassName;
        try{
            //直接去找真实存在的Event class对象
            eventClassName = Class.forName(className);
        }catch (ClassNotFoundException e){
            throw new BeansException("wrong event class name:" + className);
        }
        //判断eventClassName 对象表示的类或接口指定的event.getClass 参数所表示的类或接口是否相同，或者是否是其超类或接口
       //isAssignableFrom是用来判断子类和父类的关系的，或者接口的实现类和接口的关系的，默认所有的类的终极父类都是Object。如果A.isAssignableFrom(B)结果是true，证明B可以转换成为A,也就是A可以由B转换而来。
        //这个方法是用来比较  A.class 跟 B.class 的关系的，属于 Class对象的方法，而 instanceof属于二元运算符，用来比较  对象 跟 类的关系
        return eventClassName.isAssignableFrom(event.getClass());
    }
}
